package historymanager.tools;

import org.apache.log4j.Logger;

import historymanager.servlets.ProgramInfo;
import historymanager.tools.Configuration;
import historymanager.tools.MeasurePointRequestorController;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URLConnection;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.*;
import java.text.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.naming.*;

import historymanager.model.MeasurePoint;
import historymanager.model.ControllerUnit;

public class MeasurePointRequestor implements Runnable {
	static Logger log = Logger.getLogger(MeasurePointRequestor.class);
	public Connection con;
	public Statement stmt1, stmt2;
	ResultSet rs1, rs2;
	Configuration myConfiguration;
	private boolean myGoon = true;
	private MeasurePointRequestorController myController;
	List<MeasurePoint> mpList = new ArrayList<MeasurePoint>();// Create list of
																// measure-points
	ProgramInfo programInfo = ProgramInfo.getInstance();

	public MeasurePointRequestor(
			MeasurePointRequestorController measurePointRequestorController) {
		log.debug("Constuctor MeasurePointRequestor was called ...");
		myController = measurePointRequestorController;
		myConfiguration = Configuration.getInstance();
	}

	public void run() {

		try {
			GenerateMeasurePoints();
			GetData();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void GenerateMeasurePoints() throws Exception {

		long IDMeasurepoint;
		long IDServer;
		String symbolname;
		String type;
		int registerAddress;
		String aliasName;
		String format;
		int decimaldigits;
		String unit;
		long serverID;
		String serverAdress;
		String servername;
		String serveralias;
		int serveractive;

		try {
			Context envContext;

			log.debug("Start generate measurepoints");
			envContext = new InitialContext();
			DataSource ds = (DataSource) envContext.lookup(myConfiguration
					.getDataSourceContext());
			con = ds.getConnection(); // Datenbank-Verbindung erstellen
			stmt1 = con.createStatement();
			stmt2 = con.createStatement();

			rs1 = stmt1 // Datensatz mit allen DP abrufen die Aktiv sind
					.executeQuery("Select * from measurepoint WHERE active=1");

			while (rs1.next()) {
				IDMeasurepoint = rs1.getLong("id");
				IDServer = rs1.getLong("controllerunit");
				symbolname = rs1.getString("symbolname");
				type = rs1.getString("type");
				registerAddress = rs1.getInt("registeraddress");
				aliasName = rs1.getString("aliasname");
				format = rs1.getString("format");
				decimaldigits = rs1.getInt("decimaldigits");
				unit = rs1.getString("unit");

				rs2 = stmt2
						.executeQuery("Select * from controllerunit WHERE id="
								+ IDServer);
				rs2.next(); // An den Anfang vom Datensatz springen
				serverID = rs2.getLong("id");
				serverAdress = rs2.getString("serveraddress");
				servername = rs2.getString("stationname");
				serveralias = rs2.getString("stationalias");
				serveractive = rs2.getInt("active");
				ControllerUnit controllerunit = new ControllerUnit(serverID,
						serverAdress, servername, serveralias, serveractive); // neues
																				// Objekt
																				// vom
																				// Typ
																				// ControllerUnit
																				// erstellen

				MeasurePoint measurepoint = new MeasurePoint(IDMeasurepoint,
						controllerunit, symbolname, aliasName, type,
						registerAddress, format, decimaldigits, unit);
				mpList.add(measurepoint);
			}

		}

		catch (SQLException e) {
			log.error("SQL-Error while update and insert measurepoints into database");
		}
		log.debug(mpList.size() + " MeasurePoints created");
		programInfo.setmeasurepointCount(mpList.size()); // Anzahl der
															// angelegten
															// Datenpunkte in
															// ProgramInfo
															// schreiben
	} // End GenerateMeasurePoint

	public void GetData() {

		MeasurePoint actMeasurePoint;
		String inputLine;
		long longValue;
		double doubleValue;
		String insertSQL;
		int cycle = 0;
		long startTime;
		long endTime;
		long sleepTime;
		long runTime;
		long interval = myConfiguration.getMeasureRequestInterval();
		SimpleDateFormat date = new SimpleDateFormat("HH:mm:ss");
		String startClock, endClock;

		programInfo.setRequestInterval(interval); // Interval-Zeit in
													// ProgramInfo schreiben
		programInfo.setDatabaseMinFreeSpace(myConfiguration
				.getDatabaseMinFreeSpace());

		while (myGoon) { // Loop zum Abruf aller Daten
			startClock = date.format(new Date()); // Start-Uhrzeit speichern
			log.debug("Query-Cycle:" + String.valueOf(++cycle) + " Time: "
					+ startClock);
			startTime = System.currentTimeMillis();
			programInfo.setDatabaseSpace();// Datenbank-Speicher aktualisieren

			if (programInfo.getDatabasefreeSpace() >= myConfiguration
					.getDatabaseMinFreeSpace()) {
				programInfo.setdatabaseStatus("Datenabruf"); // Datenbank-Status
																// in
																// ProgramInfo

				for (int i = 0; i < mpList.size(); i++) {
					actMeasurePoint = mpList.get(i);
					// log.debug("Performing request for url:"
					// + actMeasurePoint.getReadValUrl());
					try {
						URLConnection uc = actMeasurePoint.getReadValUrl()
								.openConnection();
						uc.setConnectTimeout(myConfiguration.getUrlTimeOutn());
						uc.setReadTimeout(myConfiguration.getUrlTimeOutn());
						BufferedReader in = new BufferedReader(
								new InputStreamReader(uc.getInputStream()));
						inputLine = in.readLine();
						longValue = Long.parseLong(inputLine);
						doubleValue = MeasurePoint.getDoubleValue(
								actMeasurePoint, longValue);
						insertSQL = "INSERT INTO measure (measurepoint, val)"
								+ " VALUES(" + actMeasurePoint.getId() + ", "
								+ String.valueOf(doubleValue) + ")";
						stmt1.execute(insertSQL);

					} catch (SQLException e) {
						log.error("Error: Can't insert measuere in database"); // Error
																				// Datenbank-Fehler
					} catch (MalformedURLException e) {
						log.error("Error: Can't connect to station "
								+ actMeasurePoint.getReadValUrl());// Error
																	// Station
																	// nicht
																	// erreichbar
					} catch (IOException e) {
						log.error("Error: No input-stream from measurepoint "
								+ actMeasurePoint.getReadValUrl()); // Error
																	// keine
																	// Daten
																	// bekommen
					}
				}
				endClock = date.format(new Date());
				endTime = System.currentTimeMillis();
				runTime = endTime - startTime; // Laufzeit in milli-Sekunden
												// berechnen
				sleepTime = interval - runTime; // Wartezeit berechnen
				log.debug("Dauer letzter Datenabruf: " + runTime / 1000
						+ " Sekunden");
				log.debug("Time Start: " + startClock + " Time End: "
						+ endClock);
				if (sleepTime < 0) {
					sleepTime = 0;
					log.error("Zeitüberschreitung beim Datenabruf. Zeitintervall zu klein");
					log.error("Dauer letzter Datenabruf: " + runTime / 1000);
				}
				programInfo.settimeLastRequest(runTime / 1000);
				programInfo.setDateLastRequest(startClock);

				try {
					Thread.sleep(sleepTime);
				} catch (InterruptedException e) {
					log.error("Error while Thread.sleep");
				}
			} else {
				programInfo
						.setdatabaseStatus("Datenbankspeicher zu gering. Datenabruf gestoppt. Alte Daten löschen.");
				log.debug("Database full. Database free space "
						+ programInfo.getDatabasefreeSpace()
						+ " Min database frees space "
						+ myConfiguration.getDatabaseMinFreeSpace());
				stop(); // Datenabruf stoppen
			}
		}
	}

	public void stop() {
		myGoon = false;
	}
}
